//////////////////////////////////////////////////////////////////////////////
//
// Copyright © 1998-2024 Glodon.
//
// Permission is hereby granted, free of charge, to any person obtaining a
// copy of this software and associated documentation files (the “Software”),
// to deal in the Software without restriction, including without limitation
// the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
// sell copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED “AS IS”, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
// THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
//
//////////////////////////////////////////////////////////////////////////////


#if Gdmp || Gnuf
using Glodon.Gdmp.DB;
using Glodon.Gdmp.UI;
#elif Gap
using Glodon.Gap.DB;
using Glodon.Gap.UI;
#endif

using Glodon.Lookup.Services.Contracts;

namespace Glodon.Lookup.Lookup.Core
{
    public static class GlodonAPI
    {
        public static IList<ElementId> PreSelection { get; set; }
        public static UIDocument UiDocument
        {
            get
            {
                UIDocument activeUIDocument = UIApplication.Get().ActiveUIDocument;
                bool valid = activeUIDocument != null && activeUIDocument.IsValidObject();
                return (valid ? activeUIDocument : null)!;
            }
        }

        public static Document? Document => Application.Get().ActiveDocument;
        public static ModelView? ActiveView => Application.Get().ActiveDocument?.GetElement(UIApplication.Get().ActiveUIDocument.CurrentUIView.ModelViewId) as ModelView;

        public static IReadOnlyCollection<UniIdentity> CategoriesCannotShow { get; set; }

        #region 事件注册和解注册

        public static void RegistHandlers(IApiEventHandler apiEventHandler)
        {
            if (Document != null)
            {
                Document.DocumentChanged += apiEventHandler!.OnDocumentChanged;
            }
            UIApplication.Get().SelectionChanged += apiEventHandler!.OnDocumentSelectionChanged;
            UIApplication.Get().UIViewActivated += apiEventHandler.OnUIViewActivated;
            Application.Get().DocumentOpened += apiEventHandler.OnDocumentOpened;
            Application.Get().DocumentClosed += apiEventHandler.OnDocumentClosed;
        }

        public static void DeregistHandlers(IApiEventHandler apiEventHandler)
        {
            if (Document != null)
            {
                Document.DocumentChanged -= apiEventHandler!.OnDocumentChanged;
            }
            UIApplication.Get().SelectionChanged -= apiEventHandler!.OnDocumentSelectionChanged;
            UIApplication.Get().UIViewActivated -= apiEventHandler.OnUIViewActivated;
            Application.Get().DocumentOpened -= apiEventHandler.OnDocumentOpened;
            Application.Get().DocumentClosed -= apiEventHandler.OnDocumentClosed;
        }

        #endregion

        #region 获取图元Body
        public static IList<GraphicsNode>? GetGraphicsNode(Element element)
        {
            //获取图元图形节点。
            var op = new GeometryOptions();
            op.ComputeReferences = true;
            List<UniIdentity> categoriesNeedModelView = new List<UniIdentity>();
            if (element.Category != null && categoriesNeedModelView.Contains(element.Category.UId))
            {
                op.ModelView = ActiveView;
            }
            GraphicsElementShape geometry = element.GetGeometry(op);
            if (geometry == null) return null;
            //获取所有节点。
            IList<GraphicsNode> nodes = geometry.GetNodes();
            return nodes;
        }
        public static void GetBody(Document document, GraphicsNode node, List<Body> bodies)
        {
            // 若节点就是体的图形节点，则直接添加。
            if (node is GraphicsBody)
            {
                bodies.Add(((GraphicsBody)node).Body);
            }
            // 若是图形节点组，则需要继续遍历获取体的图形节点。
            if (node is GraphicsNodeGroup)
            {
                GraphicsNodeGroup nodeGroup = (GraphicsNodeGroup)node;
                if (nodeGroup != null)
                {
                    IList<GraphicsNode> groups = nodeGroup.GetNodes();
                    foreach (var n in groups)
                    {
                        GetBody(document, n, bodies);
                    }
                }
            }
            // 若是图元图形节点，则在节点集合中添加体的图形节点。
            if (node is GraphicsElementShape)
            {
                GraphicsElementShape nodeShape = (GraphicsElementShape)node;
                IList<GraphicsNode> groups = nodeShape.GetNodes();
                foreach (var n in groups)
                {
                    GetBody(document, n, bodies);
                }
            }
            // 若是图元图形节点引用，则需要获取所引用的源图元。
            if (node is GraphicsElementShapeReference)
            {
                GraphicsElementShapeReference nodeShapeReference = (GraphicsElementShapeReference)node;
                ElementId referenceId = nodeShapeReference.ElementId;
                Element referenceElem = document.GetElement(referenceId);
                GraphicsElementShape referenceGeometry = referenceElem.GetGeometry(null);
                IList<GraphicsNode> referenceNodes = referenceGeometry.GetNodes();
                foreach (var n in referenceNodes)
                {
                    if (n is GraphicsBody)
                    {
                        Body body = ((GraphicsBody)n).Body;
                        Body transformedBody = body.CreateTransformed(nodeShapeReference.Transform);
                        bodies.Add(transformedBody);
                    }
                }
            }
        }
        public static Body? GetBody(Element element)
        {
            Document document = element.Document;
            // 获取图元图形节点。
            GraphicsElementShape geometry = element.GetGeometry(null);
            if (geometry == null) return null;
            // 获取所有节点。
            IList<GraphicsNode> nodes = geometry.GetNodes();
            List<Body> bodies = new List<Body>();
            foreach (var node in nodes)
            {
                GetBody(document, node, bodies);
            }
            if (!bodies.Any()) return null;
            return bodies.OrderByDescending(x => x.Volume).FirstOrDefault();
        }
        #endregion
    }
}
